﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Microsoft.WowAddonStudio.FrameXml.Services;

namespace Microsoft.WowAddonStudio.FrameXml.Components.Editors
{
	/// <summary>
	/// The editor form to get relative paths.
	/// </summary>
	public partial class TreePickerEditorForm : Form
	{
		private string relativePath;
		private bool navigate = true;
        private readonly FrameXmlImageService imageService;

	    protected IServiceProvider provider;

		/// <summary>
		/// Initializes a new instance of the <see cref="TreePickerEditorForm"/> class.
		/// </summary>
		/// <param name="tree">The tree.</param>
		/// <param name="provider">Service provider which provides the image service.</param>
		public TreePickerEditorForm(PickerElement tree, IServiceProvider provider)
		{
            if (provider == null)
                throw new ArgumentNullException("provider");

			InitializeComponent();

		    this.provider = provider;

			//Retrieve image service...
			imageService = provider.GetService(typeof (FrameXmlImageService)) as FrameXmlImageService;

			if (imageService == null)
				throw new ApplicationException("Provider cannot find an image service.");

			//Create icon from bitmap resource
			using (var bitmap = Resources.Control_PictureBox)
			{
				bitmap.MakeTransparent(Color.Magenta);
				Icon = Icon.FromHandle(bitmap.GetHicon());
			}

			//Initialize ImageList elements
			presenterTreeView.ImageList.Images.AddRange(
				new Image[]
					{
						Resources.Control_FolderBrowserDialog,
						Resources.Control_PictureBox,
                        Resources.folder_shut
					});

			previewPictureBox.SizeMode = PictureBoxSizeMode.CenterImage;

            // Sets the tree view sorter.
		    presenterTreeView.TreeViewNodeSorter = new TreeViewSorter();

			//Create the root node and children of the TreeView
			CreateNodes(tree);
		}

		/// <summary>
		/// Gets or sets the relative path.
		/// </summary>
		/// <value>The relative path.</value>
		public string RelativePath
		{
			get{ return relativePath.Replace(".blp",String.Empty); }
			internal set
			{
				relativePath = value;
				
                //Navigates the new path.
				Navigate(relativePath);
			}
		}

		/// <summary>
		/// Navigates the specified path.
		/// </summary>
		/// <param name="path">The path.</param>
		protected void Navigate(string path)
		{
			if (!string.IsNullOrEmpty(path) && navigate)
			{
				try
				{
					PickerElement element = new FolderPickerElement("Interface");
					if (String.IsNullOrEmpty(Path.GetExtension(path)))
						path += ".blp";
                    
					element.Add(new ResourceFile(path, path, ResourceFileType.Undefined));

					NavigateTree(element, presenterTreeView.Nodes[0]);
				}
				catch (Exception ex)
				{
					Trace.WriteLine(ex);
				}
			}
		}

		/// <summary>
		/// Navigates the tree.
		/// </summary>
		/// <param name="element">The element.</param>
		/// <param name="node">The node.</param>
		private void NavigateTree(PickerElement element, TreeNode node)
		{
			if (element != null)
			{
				TreeNode treeNode = FindNode(node, element.DisplayName);
				if (treeNode != null)
				{
					ExtractChildElements(treeNode);
					presenterTreeView.SelectedNode = treeNode;

					if (element.HasChild)
					{
						IEnumerable<PickerElement> children = element.GetChildren;
						foreach (PickerElement pickerElement in children)
						{
							NavigateTree(pickerElement, treeNode);
						}
					}
				}
			}
		}

		/// <summary>
		/// Finds the node.
		/// </summary>
		/// <param name="node">The node.</param>
		/// <param name="nodeName">Name of the control.</param>
		/// <returns></returns>
		public TreeNode FindNode(TreeNode node, string nodeName)
		{
			if (node == null)
				throw new ArgumentNullException("node");

			TreeNode treeNode = null;
			if (node.Text == nodeName)
			{
				treeNode = node;
			}
			else
			{
				if (node.Nodes.Count > 0)
				{
					foreach (TreeNode subNode in node.Nodes)
					{
						treeNode = FindNode(subNode, nodeName);
						if (treeNode != null)
							return treeNode;
					}
				}
			}
			return treeNode;
		}

		/// <summary>
		/// Creates the root node.
		/// </summary>
		/// <param name="tree">The tree.</param>
		protected void CreateNodes(PickerElement tree)
		{
			if (tree == null)
				throw new ArgumentNullException("tree");

			var node = new TreeNode
			                	{
			                		Tag = tree,
			                		Text = tree.DisplayName
			                	};

			presenterTreeView.Nodes.Add(node);

			AddChildNodes(presenterTreeView.Nodes[0],
			              tree as FolderPickerElement);

			presenterTreeView.Sorted = true;
			presenterTreeView.Nodes[0].Expand();
		}

		/// <summary>
		/// Adds the child nodes.
		/// </summary>
		/// <param name="parentNode">The parent node.</param>
		/// <param name="folder">The folder.</param>
		private static void AddChildNodes(TreeNode parentNode, PickerElement folder)
		{
			if (folder != null)
			{
				parentNode.Nodes.Clear();

				foreach (var child in folder.GetChildren)
				{
					var node = new TreeNode {Tag = child, Text = child.DisplayName};
                    
					if (child is FolderPickerElement)
						node.Nodes.Add(new TreeNode());

				    if (node.Tag is LeafPickerElement)
				        node.ImageIndex = node.SelectedImageIndex = 1;
				    else
				        node.ImageIndex = node.SelectedImageIndex = child.ResourceFileType == ResourceFileType.AddOn ? 2 : node.ImageIndex;

				    parentNode.Nodes.Add(node);
				}
			}
		}

		/// <summary>
		/// Handles the Click event of the okButton control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void okButton_Click(object sender, EventArgs e)
		{
			Close();
			DialogResult = DialogResult.OK;
		}

		/// <summary>
		/// Handles the Click event of the cancelButton control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void cancelButton_Click(object sender, EventArgs e)
		{
			Close();
			DialogResult = DialogResult.Cancel;
		}

		/// <summary>
		/// Handles the BeforeExpand event of the presenterTreeView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.TreeViewCancelEventArgs"/> instance containing the event data.</param>
		private void presenterTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
		{
			ExtractChildElements(e.Node);
		}

		/// <summary>
		/// Extracts the child elements.
		/// </summary>
		/// <param name="node">The node.</param>
		protected virtual void ExtractChildElements(TreeNode node)
		{
			if (node.Nodes.Count == 1)
			{
				var folder = node.Tag as FolderPickerElement;
				AddChildNodes(node, folder);
			}
		}

		/// <summary>
		/// Handles the AfterSelect event of the presenterTreeView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.TreeViewEventArgs"/> instance containing the event data.</param>
		private void presenterTreeView_AfterSelect(object sender, TreeViewEventArgs e)
		{
			navigate = false;
			if (e.Node.Tag is FolderPickerElement)
			{
				okButton.Enabled = false;
				RelativePath = null;
			}
			if (e.Node.Tag is LeafPickerElement)
			{
				okButton.Enabled = true;
				RelativePath = (e.Node.Tag as LeafPickerElement).RelativePath;
			}

			this.ShowPreview();
			navigate = true;
		}

		/// <summary>
		/// Handles the Click event of the expandAllToolStripMenuItem control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void expandAllToolStripMenuItem_Click(object sender, EventArgs e)
		{
			try
			{
				presenterTreeView.BeginUpdate();
				presenterTreeView.ExpandAll();
			}
			finally
			{
				presenterTreeView.EndUpdate();
			}
		}

		/// <summary>
		/// Handles the Click event of the collapseAllToolStripMenuItem control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e)
		{
			presenterTreeView.CollapseAll();
		}

		/// <summary>
		/// Handles the DoubleClick event of the presenterTreeView control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void presenterTreeView_DoubleClick(object sender, EventArgs e)
		{
			if (presenterTreeView.SelectedNode != null)
			{
				if (presenterTreeView.SelectedNode.Tag is LeafPickerElement)
				{
					navigate = false;
					RelativePath = (presenterTreeView.SelectedNode.Tag as LeafPickerElement).RelativePath;
					navigate = true;
					okButton.PerformClick();
				}
			}
		}

        /// <summary>
        /// Shows the preview.
        /// </summary>
        protected virtual void ShowPreview()
        {
        }
	}
}